package com.quick.android.activity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.quick.android.app.ActivityManager;
import com.quick.android.fragment.BaseFragment;

public abstract class BaseFragmentActivity extends FragmentActivity {

	protected FragmentManager mFManager;
	private HashMap<Integer, ArrayList<String>> mStackFragments;
	private HashMap<Integer, String> mCurrentFragments;
	private int mResId = -1;

	@SuppressLint({ "UseSparseArrays" })
	protected final void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		this.mFManager = getSupportFragmentManager();
		if (savedInstanceState != null) {
			this.mStackFragments = ((HashMap) savedInstanceState
					.get("BaseFragmentActivity_mStackFragments"));
			this.mCurrentFragments = ((HashMap) savedInstanceState
					.get("BaseFragmentActivity_mCurrentFragments"));
		}
		if (this.mStackFragments == null) {
			this.mStackFragments = new HashMap();
		}
		if (this.mCurrentFragments == null) {
			this.mCurrentFragments = new HashMap();
		}
		for (Map.Entry<Integer, String> entry : this.mCurrentFragments
				.entrySet()) {
			int resId = ((Integer) entry.getKey()).intValue();
			String tag = (String) entry.getValue();
			changeFragment(resId, findFragmentByTag(resId, tag), tag);
		}
		initCreate(savedInstanceState);
		ActivityManager.getInstance().addActivity(this);

	}

	protected void initCreate(Bundle savedInstanceState) {
		initViews();
		getIntentData();
		initData(savedInstanceState);
	}

	/** 初始化界面和控件 */
	public abstract void initViews();

	/** 获取Intent传送的参数 */
	public abstract void getIntentData();

	/** 初始化数据 */
	public abstract void initData(Bundle savedInstanceState);

	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putSerializable("BaseFragmentActivity_mStackFragments",
				this.mStackFragments);
		outState.putSerializable("BaseFragmentActivity_mCurrentFragments",
				this.mCurrentFragments);
	}

	public void onBackPressed() {

		ArrayList<String> stack = (ArrayList) this.mStackFragments.get(Integer
				.valueOf(this.mResId));
		if ((stack == null) || (stack.size() == 0)) {
			finish();
		} else {
			String top = (String) stack.get(stack.size() - 1);
			BaseFragment fragment = findFragmentByTag(this.mResId, top);
			fragment.onBackPressed();
		}
	}

	protected void onDestroy() {
		super.onDestroy();
	}

	public int size() {
		return size(this.mResId);
	}

	public int size(int resId) {
		ArrayList<String> stack = (ArrayList) this.mStackFragments.get(Integer
				.valueOf(resId));
		if (stack == null) {
			return 0;
		}
		return stack.size();
	}

	public final void setFragmentViewId(int resId) {
		this.mResId = resId;
	}

	public final BaseFragment findFragmentById() {
		return findFragmentById(this.mResId);
	}

	public final BaseFragment findFragmentById(int resId) {
		return (BaseFragment) this.mFManager.findFragmentById(resId);
	}

	public final BaseFragment findFragmentByTag(String tag) {
		return findFragmentByTag(this.mResId, tag);
	}

	public final BaseFragment findFragmentByTag(int resId, String tag) {
		return (BaseFragment) this.mFManager.findFragmentByTag(resId + "@"
				+ tag);
	}

	public final BaseFragment getCurrentFragment() {
		return getCurrentFragment(this.mResId);
	}

	public final BaseFragment getCurrentFragment(int resId) {
		return findFragmentByTag(resId,
				(String) this.mCurrentFragments.get(Integer.valueOf(resId)));
	}

	public void onCreateAnimation(int resId, BaseFragment enterFragment,
			BaseFragment exitFragment, FragmentTransaction transaction,
			boolean remove) {
	}

	public final BaseFragment replaceFragment(BaseFragment fragment) {
		return replaceFragment(this.mResId, fragment, fragment.getClass()
				.getName());
	}

	public final BaseFragment replaceFragment(int resId, BaseFragment fragment) {
		return replaceFragment(resId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment replaceFragment(BaseFragment fragment, String tag) {
		return replaceFragment(this.mResId, fragment, tag);
	}

	public final BaseFragment replaceFragment(int resId, BaseFragment fragment,
			String tag) {
		FragmentTransaction ft = this.mFManager.beginTransaction();

		BaseFragment exitFragment = null;
		String exitTag = (String) this.mCurrentFragments.get(Integer
				.valueOf(resId));
		if (exitTag != null) {
			exitFragment = findFragmentByTag(resId, exitTag);
		}
		onCreateAnimation(resId, fragment, exitFragment, ft, false);
		this.mCurrentFragments.put(Integer.valueOf(resId), tag);

		ft.replace(resId, fragment, resId + "@" + tag);
		ft.commitAllowingStateLoss();

		return fragment;
	}

	public final BaseFragment changeFragment(BaseFragment fragment) {
		return changeFragment(this.mResId, fragment, fragment.getClass()
				.getName());
	}

	public final BaseFragment changeFragment(int resId, BaseFragment fragment) {
		return changeFragment(resId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment changeFragment(BaseFragment fragment, String tag) {
		return changeFragment(this.mResId, fragment, tag);
	}

	public final BaseFragment changeFragment(int resId, BaseFragment fragment,
			String tag) {
		FragmentTransaction ft = this.mFManager.beginTransaction();
		BaseFragment exitFragment = null;
		String exitTag = (String) this.mCurrentFragments.get(Integer
				.valueOf(resId));
		if (exitTag != null) {
			exitFragment = findFragmentByTag(resId, exitTag);
		}
		onCreateAnimation(resId, fragment, exitFragment, ft, false);
		this.mCurrentFragments.put(Integer.valueOf(resId), tag);
		if (this.mFManager.getFragments() != null) {
			for (Fragment f : this.mFManager.getFragments()) {
				if ((f != null) && (f.getId() == resId)) {
					ft.hide(f);
				}
			}
		}
		if (findFragmentByTag(resId, tag) == null) {
			ft.add(resId, fragment, resId + "@" + tag);
		} else {
			fragment = findFragmentByTag(resId, tag);
		}
		ft.show(fragment);
		ft.commitAllowingStateLoss();

		return fragment;
	}

	public final BaseFragment putFragment(BaseFragment fragment) {
		return putFragment(this.mResId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment putFragment(int resId, BaseFragment fragment) {
		return putFragment(resId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment putFragment(BaseFragment fragment, String tag) {
		return putFragment(this.mResId, fragment, tag);
	}

	public final BaseFragment putFragment(int resId, BaseFragment fragment,
			String tag) {
		ArrayList<String> stack = (ArrayList) this.mStackFragments.get(Integer
				.valueOf(resId));
		if (stack == null) {
			stack = new ArrayList();
			this.mStackFragments.put(Integer.valueOf(resId), stack);
		}
		tag = tag + "#" + stack.size();

		FragmentTransaction ft = this.mFManager.beginTransaction();
		BaseFragment exitFragment = null;
		String exitTag = (String) this.mCurrentFragments.get(Integer
				.valueOf(resId));
		if (exitTag != null) {
			exitFragment = findFragmentByTag(resId, exitTag);
		}
		onCreateAnimation(resId, fragment, exitFragment, ft, false);
		this.mCurrentFragments.put(Integer.valueOf(resId), tag);
		if (this.mFManager.getFragments() != null) {
			for (Fragment f : this.mFManager.getFragments()) {
				if ((f != null) && (f.getId() == resId)) {
					ft.hide(f);
				}
			}
		}
		ft.add(resId, fragment, resId + "@" + tag);
		ft.commitAllowingStateLoss();

		stack.add(tag);

		return fragment;
	}

	public final BaseFragment popFragment() {
		return popFragment(this.mResId);
	}

	public final BaseFragment popFragment(int resId) {
		ArrayList<String> stack = (ArrayList) this.mStackFragments.get(Integer
				.valueOf(resId));
		if ((stack == null) || (stack.size() <= 1)) {
			finish();
			return null;
		}
		String exitTag = (String) stack.get(stack.size() - 1);
		String enterTag = (String) stack.get(stack.size() - 2);

		FragmentTransaction ft = this.mFManager.beginTransaction();
		BaseFragment enterFragment = findFragmentByTag(resId, enterTag);
		BaseFragment exitFragment = findFragmentByTag(resId, exitTag);
		onCreateAnimation(resId, enterFragment, exitFragment, ft, true);

		ft.remove(exitFragment);
		ft.show(enterFragment);
		ft.commitAllowingStateLoss();

		this.mCurrentFragments.put(Integer.valueOf(resId), enterTag);
		stack.remove(stack.size() - 1);

		return enterFragment;
	}

	public final BaseFragment addFragment(BaseFragment fragment) {
		return addFragment(this.mResId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment addFragment(int resId, BaseFragment fragment) {
		return addFragment(resId, fragment, fragment.getClass().getName());
	}

	public final BaseFragment addFragment(BaseFragment fragment, String tag) {
		return addFragment(this.mResId, fragment, tag);
	}

	public final BaseFragment addFragment(int resId, BaseFragment fragment,
			String tag) {
		FragmentTransaction ft = this.mFManager.beginTransaction();
		ft.add(resId, fragment, resId + "@" + tag);
		ft.commitAllowingStateLoss();
		return fragment;
	}

	public final BaseFragment removeFragment(BaseFragment fragment) {
		return removeFragment(this.mResId, fragment);
	}

	public final BaseFragment removeFragment(int resId, BaseFragment fragment) {
		FragmentTransaction ft = this.mFManager.beginTransaction();
		ft.remove(fragment);
		ft.commitAllowingStateLoss();
		return fragment;
	}
}
